package main.leetcode.clockin.September;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 40. 组合总和 II
 *
 * <p>给定一个数组 candidates 和一个目标数 target ，找出 candidates 中所有可以使数字和为 target 的组合。
 *
 * <p>candidates 中的每个数字在每个组合中只能使用一次。
 *
 * <p>说明：所有数字（包括目标数）都是正整数。 解集不能包含重复的组合。
 *
 * <p>示例 1: 输入: candidates = [10,1,2,7,6,1,5], target = 8, 所求解集为: [ [1, 7], [1, 2, 5], [2, 6], [1,
 * 1, 6] ]
 *
 * <p>示例 2: 输入: candidates = [2,5,2,1,2], target = 5, 所求解集为: [ [1,2,2], [5] ]
 */
public class day10 {
    private List<List<Integer>> res;

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        res = new ArrayList<>();
        if (candidates == null || candidates.length < 1) {
            return res;
        }
        Arrays.sort(candidates);
        backTrack(candidates, target, 0, 0, new ArrayList<>());
        return res;
    }

    private void backTrack(int[] candidates, int tar, int cur, int index, List<Integer> list) {
        if (cur == tar) {
            res.add(new ArrayList<>(list));
            return;
        }
        for (int i = index; i < candidates.length && cur + candidates[i] <= tar; ++i) {
            // 在此轮遍历中，后续遇到相同的数直接跳过，index 与 index - 1 相同的数，无需跳过
            if (i > index && candidates[i] == candidates[i - 1]) {
                continue;
            }
            int num = candidates[i];
            list.add(num);
            backTrack(candidates, tar, cur + num, i + 1, list);
            list.remove(list.size() - 1);
        }
    }

    //    /** Set */
    //    private Set<List<Integer>> set;
    //
    //    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    //        set = new HashSet<>();
    //        List<List<Integer>> res = new ArrayList<>();
    //        if (candidates == null || candidates.length < 1) {
    //            return res;
    //        }
    //        Arrays.sort(candidates);
    //        backTrack(candidates, target, 0, 0, new ArrayList<>());
    //        res = new ArrayList<>(set);
    //        return res;
    //    }
    //
    //    private void backTrack(int[] candidates, int tar, int cur, int index, List<Integer> list)
    // {
    //        if (cur == tar) {
    //            set.add(new ArrayList<>(list));
    //            return;
    //        }
    //        for (int i = index; i < candidates.length; ++i) {
    //            int num = candidates[i];
    //            if (cur + num > tar) {
    //                break;
    //            }
    //            list.add(num);
    //            backTrack(candidates, tar, cur + num, i + 1, list);
    //            list.remove(list.size() - 1);
    //        }
    //    }
}
